home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
smailsrc.zip
/
UUPC.ZIP
/
DCPGPKT.C
< prev
next >
Wrap
Text File
|
1990-04-21
|
19KB
|
757 lines
/*
For best results in visual layout while viewing this file, set
tab stops to every 8 columns.
*/
/*
dcpgpkt.c
Revised edition of dcp
Stuart Lynne May/87
Copyright (c) Richard H. Lamb 1985, 1986, 1987
Changes Copyright (c) Stuart Lynne 1987
Maintenance notes:
25Aug87 - Allow for up to 7 windows - Jal
01Nov87 - those strncpy's should really be memcpy's! - Jal
*/
/* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
/*
* Cleaned up by Stephen Trier, April 21, 1990
*/
/* 7-window "g" ptotocol */
/*
Thanks goes to John Gilmore for sending me a copy of Greg Chesson's
UUCP protocol description -- Obviously invaluable.
Thanks also go to Andrew Tannenbaum for the section on Siding window
protocols with a program example in his "Computer Networks" book.
*/
#include "dcp.h"
#define PKTSIZE 64
#define PKTSIZ2 2 /* 8x(2**2) = 64 */
#define HDRSIZE 6
#define MAXTRY 4
/* g-packet type definitions */
#define DATA 0
#define CLOSE 1
#define NAK 2
#define SRJ 3
#define ACK 4
#define INITC 5
#define INITB 6
#define INITA 7
#define MAXERR 200 /* Don't want to quit in a middle of a long file */
#define TIMEOUT 4 /* could be longer */
#define KPKT 1024/PKTSIZE
#define POK -1
#define MAXWINDOW 7
#define SWINDOW 3 /* fixed now, you make it variable! (done.) */
#define RWINDOW 3
#define NBUF 8 /* always SAME as MAXSEQ ? */
#define MAXSEQ 8
#define between(a,b,c) ((a<=b && b<c) || (c<a && a<=b) || (b<c && c<a))
/* packet definitions */
static int rwl, swl, swu, rwu, nerr, nbuffers, npkt, irec, timeout;
static int GOT_SYNC, GOT_HDR;
static int fseq[NBUF], outlen[NBUF], inlen[NBUF], arrived[NBUF];
static int nwindows;
static char outbuf[NBUF][PKTSIZE+1], inbuf[NBUF][PKTSIZE+1];
static unsigned char grpkt[HDRSIZE+1];
static long ftimer[NBUF], acktmr, naktmr;
static void gspack();
static int grpack(), gmachine();
/****************** SUB SUB SUB PACKET HANDLER ************/
/*
g o p e n p k
*/
int gopenpk()
{
int i, xxx, yyy, len;
char tmp[PKTSIZE+1];
pktsize = PKTSIZE; /* change it later after the init */
msgtime = MSGTIME; /* not sure I need this for "g" proto */
/* initialize proto parameters */
swl = nerr = nbuffers = npkt = 0;
swl = swu = 1;
rwl = 0;
rwu = MAXWINDOW - 1;
nwindows = MAXWINDOW;
for (i = 0; i < NBUF; i++) {
ftimer[i] = 0;
arrived[i] = FALSE;
}
GOT_SYNC = GOT_HDR = FALSE;
/* 3-way handshake */
timeout = 2; /* want some timeout capability here */
gspack(INITA, 0, 0, 0, tmp);
rsrt:
if (nerr >= MAXERR)
return(FAILED);
/* INIT sequence. Easy fix for variable packet size.
I didn't since all the machines I talk to use PKTSZ=64.
If you do this make sure to reflect the changes in "grpack"
and "gspack" */
switch (grpack(&yyy, &xxx, &len, tmp)) {
case INITA:
gspack(INITB, 0, 0, 0, tmp); /* data segment (packet) size */
nwindows = yyy;
if (nwindows > MAXWINDOW)
nwindows = MAXWINDOW;
rwu = nwindows - 1;
goto rsrt;
case INITB:
gspack(INITC, 0, 0, 0, tmp);
goto rsrt;
case INITC:
break;
default:
nerr++;
gspack(INITA, 0, 0, 0, tmp);
goto rsrt;
}
nerr = 0;
return(OK); /* channel open */
} /*gopenpk*/
/*
g c l o s e p k
*/
int gclosepk()
{
int i;
char tmp[PKTSIZE+1];
timeout = 1;
for (i = 0; i < MAXTRY; i++) {
gspack(CLOSE, 0, 0, 0, tmp);
if (gmachine() == CLOSE)
break;
}
printmsg(0, "%d packets transferred, %d errors.", npkt, nerr);
return(0);
} /*gclosepk*/
/*
g g e t p k t
Gets no more than a packet's worth of data from
the "packet I/O state machine". May have to
periodically run the packet machine to get some packets.
on input: don't care
on return: data+\0 and length in len.
ret(0) if all's well
ret(-1) if problems (failed)
*/
int ggetpkt(data, len)
char *data;
int *len;
{
int i;
irec = 1;
timeout = 0;
/* LOOP TO WAIT FOR THE DESIRED PACKET */
while ((arrived[rwl]) == FALSE)
if (gmachine() != POK)
return(-1);
/* GOT A PACKET! */
i = rwl; /*<-- mod(,rwindow) for larger than 8 seq no.s */
*len = inlen[i];
memcpy(data, inbuf[i], *len);
arrived[i] = FALSE;
rwu = (rwu + 1) % MAXSEQ; /* bump receive window */
npkt++;
return(0);
} /*ggetpkt*/
/*
g s e n d p k t
Put at most a packet's worth of data in the packet state
machine for transmission.
May have to run the packet machine a few times to get
an available output slot.
on input: data=*data; len=length of data in data.
flg = 2 just send the packet with no wait for ack.
flg > 0 zero out the unused part of the buffer. (for UUCP "msg" pkts)
flg = 0 normal data
return:
0 if all's well
-1 if problems (failed)
*/
int gsendpkt(data, len, flg)
char *data;
int len, flg;
{
int i1;
irec = 0;
timeout = 0; /* non-blocking reads */
/* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been
acked, wait for acks */
while (nbuffers >= nwindows)
if (gmachine() != POK)
return(-1);
i1 = swu; /* <--If we ever have more than 8 seq no.s, must mod() here */
/* PLACE PACKET IN TABLE AND MARK UNACKED */
/* fill with zeros or not */
if (flg) {
int i;
strcpy(outbuf[i1], data);
for (i = strlen(data); i < PKTSIZE; i++)
outbuf[i1][i] = '\0';
len = PKTSIZE;
} else {
memcpy(outbuf[i1], data, len);
outbuf[i1][len] = '\0';
}
/* mark packet */
outlen[i1] = len;
ftimer[i1] = time(nil(long));
fseq[i1] = swu;
swu = (swu + 1) % MAXSEQ; /* bump send window */
nbuffers++;
npkt++;
/* send it */
gspack(DATA, rwl, fseq[i1], outlen[i1], outbuf[i1]);
/* send it once then let the packet machine take it.
Wouldn't need this for multi-tasking systems. */
/* sl gmachine(); */
return(0);
} /*gsendpkt*/
/********** Packet Machine ********** RH Lamb 3/87 */
/*
g m a c h i n e
Ideally we would like to fork this process off in an infinite loop and
send and receive packets through "inbuf" and "outbuf". Can't do this in
MS-DOS so we setup "getpkt" and "sendpkt" to call this routine often and
return only when the input buffer is empty thus "blocking" the packet-
machine task.
*/
static int gmachine()
{
int rack, rseq, rlen, i1, i2, dflg;
char rdata[PKTSIZE+1];
long itmp;
reply:
printmsg(10, "* send %d < W < %d, receive %d < W < %d, error %d",
swl, swu, rwl, rwu, nerr);
/* waiting for ACKs for swl to swu-1. Next pkt to send=swu */
/* rwl=expected pkt */
printmsg(7, "Kbytes transfered %d errors %d", npkt / KPKT, nerr);
if (nerr >= MAXERR)
goto close;
dflg = 0;
switch (grpack(&rack, &rseq, &rlen, rdata)) {
case CLOSE:
printmsg(5, "**got CLOSE");
goto close;
case NAK:
nerr++;
acktmr = naktmr = 0; /* stop ack/nak timer */
printmsg(5, "**got NAK %d", rack);
nloop:
if (between(swl, rack, swu)) { /* resend rack->(swu-1) */
i1 = rack;
gspack(DATA, rwl, rack, outlen[i1], outbuf[i1]);
printmsg(5, "*** resent %d", rack);
ftimer[i1] = time(nil(long));
rack = (rack + 1) % MAXSEQ;
goto nloop;
}
if (dflg)
return(POK);
goto reply; /* any other stuff ? */
case EMPTY:
printmsg(5, "**got EMPTY");
itmp = time(nil(long));
if (acktmr)
if ((itmp - acktmr) >= TIMEOUT) { /* ack timed out*/
gspack(ACK, rwl, 0, 0, rdata);
acktmr = itmp;
}
if (naktmr)
if ((itmp - naktmr) >= TIMEOUT) { /*nak timed out*/
gspack(NAK, rwl, 0, 0, rdata);
naktmr = itmp;
}
/* resend any timed out un-acked pkts */
for (i2 = swl; between(swl, i2, swu); i2 = (1 + i2) % MAXSEQ) {
acktmr = naktmr = 0; /* reset ack/nak */
i1 = i2;
printmsg(5, "---> seq, elapst %d %ld", i2, (itmp - ftimer[i1]));
if ((itmp - ftimer[i1]) >= TIMEOUT) {
printmsg(5, "*** timeout %d", i2);
/* Since "g" is "go-back-N", when we time out we
must send the last N pkts in order. The generalized
sliding window scheme relaxes this reqirment. */
nerr++;
dflg = 1; /* same hack */
rack = i2;
goto nloop;
}
}
return(POK);
case ACK:
printmsg(5, "**got ACK %d", rack);
acktmr = naktmr = 0; /* disable ack/nak's */
aloop:
if (between(swl, rack, swu)) { /* S<-- -->(S+W-1)%8 */
printmsg(5, "*** ACK %d", swl);
ftimer[swl] = 0;
nbuffers--;
swl = (1 + swl) % MAXSEQ;
dflg = 1; /* same hack */ /* sl */
goto aloop;
}
if (dflg)
return(POK); /* hack for non-mtask sys's */
/* to empty "inbuf[]" */
goto reply;
case DATA:
printmsg(5, "**got DATA %d %d", rack, rseq);
i1 = (rwl + 1) % MAXSEQ; /* (R+1)%8 <-- -->(R+W)%8 */
i2 = (rwu + 1) % MAXSEQ;
if (between(i1, rseq, i2)) {
if (i1 == rseq) {
i1 = rseq;
arrived[i1] = TRUE;
inlen[i1] = rlen;
memcpy(inbuf[i1], rdata, rlen);
rwl = (rwl + 1) % MAXSEQ;
printmsg(5, "*** ACK d %d", rwl);
gspack(ACK, rwl, 0, 0, rdata);
acktmr = time(nil(long)); /* enable ack/nak tmout*/
dflg = 1; /* return to call when finished */
/* in a mtask system, unneccesary */
} else {
nerr++;
printmsg(5, "*** unexpect %d ne %d", rseq, rwl);
}
} else {
nerr++;
printmsg(5, "*** wrong seq %d", rseq);
}
goto aloop;
case ERROR:
nerr++;
printmsg(5, "*** got BAD CHK");
gspack(NAK, rwl, 0, 0, rdata);
naktmr = time(nil(long)); /* set nak timer */
printmsg(5, "*** NAK d %d", rwl);
goto reply;
default:
printmsg(5, "*** got SCREW UP");
goto reply; /* ignore it */
}
close:
gspack(CLOSE, 0, 0, 0, rdata);
return(CLOSE);
} /*gmachine*/
/*************** FRAMMING *****************************/
/*
g s p a c k
Send a packet
type=type yyy=pkrec xxx=timesent len=length<=PKTSIZE data=*data
ret(0) always
*/
static void gspack(type, yyy, xxx, len, data)
int type, yyy, xxx, len;
char data[];
{
unsigned int check, i;
unsigned char header[HDRSIZE+1];
/***** Link Testing Mods *****/
/* unsigned char dpkerr[10]; /**/
/***** End Link Testing Mods *****/
if (len > PKTSIZE) /* just in case */
len = PKTSIZE;
if (len == 0)
data[0] = '\0';
/***** Link Testing Mods - create artificial errors *****/
/* printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
gets(dpkerr);
if (dpkerr[0] == 's')
sscanf(&dpkerr[1], "%d", &xxx); /**/
/***** End Link Testing Mods *****/
printmsg(5, "send packet type %d, yyy=%d, xxx=%d, len=%d",
type, yyy, xxx, len);
printmsg(5, "data=|%s|", data);
header[0] = '\020';
type %= 8;
header[4] = type << 3;
switch (type) {
case CLOSE:
break; /* stop protocol */
case NAK:
header[4] += yyy;
break; /* reject */
case SRJ:
break;
case ACK:
header[4] += yyy;
break; /* ack */
case INITC:
header[4] += nwindows;
break;
case INITB:
header[4] += 1;
break; /* pktsiz = 64 (1) */
case INITA:
header[4] += MAXWINDOW;
break;
case DATA:
header[4] = 0x80 + (xxx << 3) + yyy;
/* havn't set it up for VERY LONG packets with a few
bytes yet (-128) */
if (len < PKTSIZE) { /* short packet? */
header[4] |= 0x40;
memmove(data + 1, data, PKTSIZE - 1);
data[0] = PKTSIZE - len;
}
break;
}
if (type != DATA) {
header[1] = 9; /* control packet size = 0 (9) */
check = (0xaaaa - header[4]) & 0xffff;
} else {
header[1] = PKTSIZ2; /* data packet size = 64 (2) */
check = checksum(data, PKTSIZE);
i = header[4]; /* got to do this on PC for ex-or high bits */
i &= 0xff;
check = (check ^ i) & 0xffff;
check = (0xaaaa - check) & 0xffff;
}
header[2] = check & 0xff;
header[3] = (check >> 8) & 0xff;
header[5] = (header[1] ^ header[2] ^ header[3] ^ header[4]) & 0xff;
/***** More Link Testing Mods *****/
/* switch(dpkerr[0]) {
case 'e':
data[10] = - data[10];
break;
case 'h':
header[5] = - header[5];
break;
case 'l':
return;
case 'p':
swrite(header, HDRSIZE);
if (header[1] != 9)
swrite(data, PKTSIZE - 3);
return;
default:
break;
} /**/
/***** End Link Testing Mods *****/
swrite(header, HDRSIZE); /* header is 6-bytes long */
if (header[1] != 9)
swrite(data, PKTSIZE); /* data is always 64 bytes long */
} /*gspack*/
/*
g r p a c k
Read packet
on return: yyy=pkrec xxx=pksent len=length<=PKTSIZE data=*data
ret(type) ok
ret(EMPTY) input buf empty
ret(ERROR) bad header
ret(EMPTY) lost packet timeout
ret(ERROR) checksum error
ret(-5) packet size != 64
NOTE (specifications for sread()):
sread(buf, n, timeout)
while(TRUE) {
if (# of chars available >= n) (without dec internal counter)
read n chars into buf (decrement internal char counter)
break
else
if (time > timeout)
break
}
return(# of chars available)
*/
static int grpack(yyy, xxx, len, data)
int *yyy, *xxx, *len;
char data[];
{
unsigned int type, check, checkchk, i;
unsigned char c, c2;
if (GOT_SYNC)
goto get_hdr;
if (GOT_HDR)
goto get_data;
do {
if (sread(&c, 1, timeout) == 0)
return(EMPTY);
} while ((c & 0x7f) != '\020');
GOT_SYNC = TRUE;
get_hdr:
if (sread(&grpkt[1], HDRSIZE - 1, timeout) < (HDRSIZE - 1))
return(EMPTY);
GOT_SYNC = FALSE;
/* i = grpkt[1] ^ grpkt[2] ^ grpkt[3] ^ grpkt[4] ^ grpkt[5]; */
i = (unsigned)grpkt[1] ^ (unsigned)grpkt[2] ^
(unsigned)grpkt[3] ^ (unsigned)grpkt[4] ^
(unsigned)grpkt[5];
i &= 0xff;
printmsg(10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
if (i != 0) { /* bad header */
printmsg(0, "*** bad header ***");
return(ERROR); /* I'm not sure whether "g" considers it an empty or error */
}
GOT_HDR = TRUE;
if (grpkt[1] == 9) { /* control packet */
*data = '\0';
*len = 0;
c = grpkt[4];
type = c >> 3;
*yyy = c & 0x07;
*xxx = 0;
check = 0;
checkchk = 0;
GOT_HDR = FALSE;
} else { /* data packet */
if (grpkt[1] != PKTSIZ2)
return(-5); /* can't handle packet size other than 64 */
get_data:
if (sread(data, PKTSIZE, timeout) < PKTSIZE)
return(EMPTY);
GOT_HDR = FALSE;
type = 0;
c2 = grpkt[4];
c = c2 & 0x3f;
*xxx = c >> 3;
*yyy = c & 0x07;
i = grpkt[3];
i = (i << 8) & 0xff00;
check = grpkt[2];
check = i | (check & 0xff);
checkchk = checksum(data, PKTSIZE);
i = grpkt[4] | 0x80;
i &= 0xff;
checkchk = 0xaaaa - (checkchk ^ i);
checkchk &= 0xffff;
if (checkchk != check) {
printmsg(4, "*** checksum error ***");
return(ERROR);
}
*len = PKTSIZE;
/* Haven't set it up for very long pkts yet (>128). RH Lamb */
if (c2 & 0x40) {
int ii;
ii = (data[0] & 0xff);
*len = (*len - ii) & 0xff;
memmove(data, data + 1, *len);
}
data[*len] = '\0';
}
printmsg(12, "receive packet type %d, yyy=%d, xxx=%d, len=%d",
type, *yyy, *xxx, *len);
printmsg(13, " checksum rec=%04x comp=%04x\ndata=|%s|",
check, checkchk, data);
return(type);
} /*grpack*/
/*
c h e c k s u m
*/
unsigned checksum(data, len)
int len;
char data[];
{
unsigned int i, j, tmp, chk1, chk2;
chk1 = 0xffff;
chk2 = 0;
j = len;
for (i = 0; i < len; i++) {
if (chk1 & 0x8000) {
chk1 <<= 1;
chk1++;
} else {
chk1 <<= 1;
}
tmp = chk1;
chk1 += (data[i] & 0xff);
chk2 += chk1 ^ j;
if ((chk1 & 0xffff) <= (tmp & 0xffff))
chk1 ^= chk2;
j--;
}
return(chk1 & 0xffff);
} /*checksum*/
#if FALSE
/*
gwrmsg - send a null terminated string out
*/
gwrmsg(typ, buf)
char typ;
char *buf; /* null terminated */
{
} /*gwrmsg*/
/*
grdmsg - read a null terminated string
*/
grdmsg(buf)
char *buf;
{
} /*grdmsg*/
/*
gwrdata - read a file and send it out
*/
gwrdata(f)
{
} /*gwrdata*/
/*
grrdata - read in data and send to file
*/
grrdata(f)
{
} /*grrdata*/
/*
grdblk - read a block of data in
*/
grdblk(blk, len)
{
} /*grdblk*/
/*
gwrblk - write out a block of data
*/
gwrblk(blk, len)
{
} /*gwrblk*/
#endif